package cc.mrbird.febs.system.service.impl;

import cc.mrbird.febs.common.authentication.JWTUtil;
import cc.mrbird.febs.common.domain.QueryRequest;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.SortUtil;
import cc.mrbird.febs.system.dao.TShopTaxInfoMapper;
import cc.mrbird.febs.system.domain.*;
import cc.mrbird.febs.system.dao.TShopMapper;
import cc.mrbird.febs.system.manager.TempInfoManager;
import cc.mrbird.febs.system.service.AreaService;
import cc.mrbird.febs.system.service.ITResidentService;
import cc.mrbird.febs.system.service.ITShopService;
import cc.mrbird.febs.system.service.ITShopTaxInfoService;
import cc.mrbird.febs.system.vo.TShopExcelVO;
import cc.mrbird.febs.system.vo.TShopVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableMap;
import com.wuwenze.poi.pojo.ExcelErrorField;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dtwei
 */
@Service
public class TShopServiceImpl extends ServiceImpl<TShopMapper, TShop> implements ITShopService {

    @Resource
    private ITShopTaxInfoService taxInfoService;

    @Resource
    private ITResidentService itResidentService;

    @Resource
    private TempInfoManager tempInfoManager;

    @Resource
    private AreaService areaService;

    @Override
    public IPage<TShopVO> findShops(TShop tShop, String areaName, String peopleName, QueryRequest request) {
        try {
            Page<TShopVO> page = new Page<>();
            SortUtil.handlePageSort(request, page, true);
            IPage<TShopVO> retPage = this.baseMapper.findShopDetails(page, tShop, areaName, peopleName);
            return retPage;
        } catch (Exception e) {
            log.error("获取店铺信息失败", e);
            return null;
        }
    }

    @Override
    public void createShop(TShopVO shop) throws Exception {
        //获取当前用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        String username = "";
        String userId = "";
        if (StringUtils.isNotBlank(token)) {
            username = JWTUtil.getUsername(token);
            userId = JWTUtil.getUserId(token);
        }

        LambdaQueryWrapper<TShop> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TShop::getShopCode, shop.getShopCode()).or().eq(TShop::getShopName, shop.getShopName());
        List<TShop> dupAreas = baseMapper.selectList(queryWrapper);
        if(dupAreas != null && dupAreas.size() >= 1) {
            String message = "新增店铺失败：店铺编码重复或者名称重复";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }
        shop.setCreateTime(new Date());
        shop.setCreateUsername(username);
        shop.setCreateUserId(Long.valueOf(userId));
        this.baseMapper.insertShop(shop);

        //税收信息
        if(null != shop.getTaxInfos() && shop.getTaxInfos().size() > 0 && null != shop.getId()) {
            shop.getTaxInfos().forEach(f -> {
                f.setShopId(shop.getId());
            });
            taxInfoService.insertTaxInfos(shop.getTaxInfos());
        }
    }

    @Override
    public void deleteShops(String[] ids) {
        taxInfoService.deleteByShopIds(Arrays.asList(ids));
        removeByIds(Arrays.asList(ids));
    }

    @Override
    public void updateShop(TShopVO shop) throws Exception {
        //获取当前用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        String username = "";
        String userId = "";
        if (StringUtils.isNotBlank(token)) {
            username = JWTUtil.getUsername(token);
            userId = JWTUtil.getUserId(token);
        }

        TShop tempArea = getById(shop.getId());
        if(tempArea == null) {
            String message = "更新店铺失败：店铺不存在";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }
        if(this.checkDup(shop.getShopCode(), shop.getShopName(), shop.getId())) {
            String message = "更新店铺失败：店铺编码重复或者店铺名称重复";
            Exception e = new FebsException(message);
            log.error(message, e);
            throw e;
        }

        // 更新店铺信息
        UpdateWrapper<TShop> upWrp = new UpdateWrapper<>();
        upWrp.set("SHOP_CODE", shop.getShopCode());
        upWrp.set("SHOP_NAME", shop.getShopName());
        upWrp.set("AREA_ID", shop.getAreaId());
        upWrp.set("STREET", shop.getStreet());
        upWrp.set("SHOP_ADR", shop.getShopAdr());
        upWrp.set("OWNER_ID", shop.getOwnerId());
        upWrp.set("OWNER_NAME", shop.getOwnerName());
        upWrp.set("OPE_ID", shop.getOpeId());
        upWrp.set("OPE_NAME", shop.getOpeName());
        upWrp.set("OPE_TYPE", shop.getOpeType());
        upWrp.set("RENT", shop.getRent());
        upWrp.set("REVENUE", shop.getRevenue());
        upWrp.set("MODIFY_TIME", new Date());
        upWrp.set("MODIFY_USERNAME", username);
        upWrp.set("MODIFY_USER_ID", userId);
        upWrp.eq("ID",shop.getId());
        this.baseMapper.update(null, upWrp);

        //税收信息
        if(null != shop.getTaxInfos() && shop.getTaxInfos().size() > 0 && null != shop.getId()) {
            shop.getTaxInfos().forEach(f -> {
                f.setShopId(shop.getId());
            });
            taxInfoService.insertTaxInfos(shop.getTaxInfos());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Map<String, Object>> importShops(List<Map<String, Object>> successList) throws Exception {
        //获取当前用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        String username = "";
        String userId = "";
        if (StringUtils.isNotBlank(token)) {
            username = JWTUtil.getUsername(token);
            userId = JWTUtil.getUserId(token);
        }

        List<Map<String, Object>> errList = new ArrayList<>();
        List<TShopVO> goodShops = new ArrayList<>();

        List<Integer> errRow = new ArrayList<>();
        for(Map<String, Object> scIt: successList) {
            TShopExcelVO entity = (TShopExcelVO) scIt.get("entity");
            int sheetIndex = (int) scIt.get("sheetIndex");
            int rowIndex = (int) scIt.get("rowIndex");

            if(!errRow.isEmpty() && errRow.contains(rowIndex)) {
                continue;
            }

            //1.商铺名称,商铺编码是否重复
            //1.1表内数据是否重复
            List<Map<String, Object>> dupItems = successList.stream().filter(f ->
                    ((int) f.get("sheetIndex") != sheetIndex) &&
                            ((int) f.get("rowIndex") != rowIndex) &&
                            (((TShopExcelVO) f.get("entity")).getShopName().equals(entity.getShopName())
                                    || ((TShopExcelVO) f.get("entity")).getShopCode().equals(entity.getShopCode()))
            ).collect(Collectors.toList());

            if (dupItems.size() > 0) {
                dupItems.forEach(f -> {
                    errRow.add((int) f.get("rowIndex"));

                    ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                    ExcelErrorField excelErrorField = new ExcelErrorField();
                    excelErrorField.setErrorMessage("表内商铺名称或者商铺编码重复");
                    excelErrorFields.add(excelErrorField);
                    errList.add(
                            ImmutableMap.of("sheetIndex", f.get("sheetIndex"),//
                                    "rowIndex", f.get("rowIndex"),//
                                    "errorFields", excelErrorFields));
                });

                errRow.add(rowIndex);

                ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                ExcelErrorField excelErrorField = new ExcelErrorField();
                excelErrorField.setErrorMessage("表内商铺名称或者商铺编码重复");
                excelErrorFields.add(excelErrorField);
                errList.add(
                        ImmutableMap.of("sheetIndex", sheetIndex,//
                                "rowIndex", rowIndex,//
                                "errorFields", excelErrorFields));
                continue;
            }

            //1.2现有数据是否重复
            List<String> shopNames = tempInfoManager.getAllShopName();
            if (shopNames.contains(entity.getShopName())) {
                errRow.add(rowIndex);

                ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                ExcelErrorField excelErrorField = new ExcelErrorField();
                excelErrorField.setErrorMessage("与已存在的商铺名称重复");
                excelErrorFields.add(excelErrorField);
                errList.add(
                        ImmutableMap.of("sheetIndex", sheetIndex,//
                                "rowIndex", rowIndex,//
                                "errorFields", excelErrorFields));
                continue;
            }

            List<String> shopCodes = tempInfoManager.getAllShopCode();
            if (shopCodes.contains(entity.getShopCode())) {
                errRow.add(rowIndex);

                ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                ExcelErrorField excelErrorField = new ExcelErrorField();
                excelErrorField.setErrorMessage("与已存在的商铺代码重复");
                excelErrorFields.add(excelErrorField);
                errList.add(
                        ImmutableMap.of("sheetIndex", sheetIndex,//
                                "rowIndex", rowIndex,//
                                "errorFields", excelErrorFields));
                continue;
            }

            //2.区域信息是否存在
            List<Area> areas = tempInfoManager.getAllArea();
            if(StringUtils.isNotBlank(entity.getAreaName())) {
                List<Area> aTmp = areas.stream().filter(f -> f.getAreaName().equals(entity.getAreaName())).collect(Collectors.toList());
                if(aTmp.size() > 0) {
                   entity.setAreaId(aTmp.get(0).getAreaId());
                } else {
                    errRow.add(rowIndex);

                    ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                    ExcelErrorField excelErrorField = new ExcelErrorField();
                    excelErrorField.setErrorMessage("所属四级片区不存在");
                    excelErrorFields.add(excelErrorField);
                    errList.add(
                            ImmutableMap.of("sheetIndex", sheetIndex,//
                                    "rowIndex", rowIndex,//
                                    "errorFields", excelErrorFields));
                    continue;
                }
            } else {
                errRow.add(rowIndex);

                ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                ExcelErrorField excelErrorField = new ExcelErrorField();
                excelErrorField.setErrorMessage("所属四级片区不存在");
                excelErrorFields.add(excelErrorField);
                errList.add(
                        ImmutableMap.of("sheetIndex", sheetIndex,//
                                "rowIndex", rowIndex,//
                                "errorFields", excelErrorFields));
                continue;
            }

            //3.商铺产权人信息是否存在
            if(StringUtils.isNotBlank(entity.getOwnerCardId())) {
                TResident rs = new TResident();
                rs.setCardId(entity.getOwnerCardId());
                List<TResident> rsTmp = itResidentService.findResidents(rs);
                if(null != rsTmp && rsTmp.size() > 0) {
                    entity.setOwnerId(rsTmp.get(0).getId());
                } else {
                    errRow.add(rowIndex);

                    ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                    ExcelErrorField excelErrorField = new ExcelErrorField();
                    excelErrorField.setErrorMessage("产权人不存在");
                    excelErrorFields.add(excelErrorField);
                    errList.add(
                            ImmutableMap.of("sheetIndex", sheetIndex,//
                                    "rowIndex", rowIndex,//
                                    "errorFields", excelErrorFields));
                    continue;
                }
            }

            //4.商铺经营人信息是否存在
            if(StringUtils.isNotBlank(entity.getOpeCardId())) {
                TResident rs = new TResident();
                rs.setCardId(entity.getOpeCardId());
                List<TResident> rsTmp = itResidentService.findResidents(rs);
                if(null != rsTmp && rsTmp.size() > 0) {
                    entity.setOpeId(rsTmp.get(0).getId());
                } else {
                    errRow.add(rowIndex);

                    ArrayList<ExcelErrorField> excelErrorFields = new ArrayList<>();
                    ExcelErrorField excelErrorField = new ExcelErrorField();
                    excelErrorField.setErrorMessage("经营人不存在");
                    excelErrorFields.add(excelErrorField);
                    errList.add(
                            ImmutableMap.of("sheetIndex", sheetIndex,//
                                    "rowIndex", rowIndex,//
                                    "errorFields", excelErrorFields));
                    continue;
                }
            }

            TShopVO shopTmp = new TShopVO();
            shopTmp.setShopCode(entity.getShopCode());
            shopTmp.setShopName(entity.getShopName());
            shopTmp.setShopAdr(entity.getShopAdr());
            shopTmp.setStreet(entity.getStreet());
            shopTmp.setAreaId(entity.getAreaId());
            shopTmp.setOwnerId(entity.getOwnerId());
            shopTmp.setOwnerName(entity.getOwnerName());
            shopTmp.setOpeId(entity.getOpeId());
            shopTmp.setOpeName(entity.getOpeName());
            shopTmp.setOpeType(entity.getOpeType());
            shopTmp.setRent(entity.getRent());
            shopTmp.setRevenue(entity.getRevenue());
            shopTmp.setCreateTime(new Date());
            shopTmp.setCreateUserId(Long.valueOf(userId));
            shopTmp.setCreateUsername(username);
            shopTmp.setTaxInfos(entity.getTaxInfo());
            goodShops.add(shopTmp);
        }

        if(errList.isEmpty() && !goodShops.isEmpty()) {
            try {
                insertShopListWithNoCheck(goodShops);
            } catch (Exception fe) {
                String message = "导入店铺失败：" + fe.getMessage();
                Exception e = new FebsException(message);
                log.error(message, e);
                throw e;
            }
        }
        return errList;
    }

    @Override
    public void insertShopListWithNoCheck(List<TShopVO> shops) throws Exception {
        this.baseMapper.insertShopList(shops);

        for(TShopVO shop: shops) {
            //税收信息
            if(null != shop.getTaxInfos() && shop.getTaxInfos().size() > 0 && null != shop.getId()) {
                shop.getTaxInfos().forEach(f -> {
                    f.setShopId(shop.getId());
                });
                taxInfoService.insertTaxInfos(shop.getTaxInfos());
            }
        }
    }

    @Override
    public List<String> findAllShopNames() {
        List<String> shopNames = this.baseMapper.selectAllShopNames();
        if(null != shopNames && shopNames.size() > 0) {
            try {
                tempInfoManager.loadAllShopNameRedisCache(shopNames);
            } catch (Exception e) {
                log.error("redis error：", e);
            }
        }
        return shopNames;
    }

    @Override
    public List<String> findAllShopCodes() {
        List<String> shopCodes = this.baseMapper.selectAllShopCodes();
        if(null != shopCodes && shopCodes.size() > 0) {
            try {
                tempInfoManager.loadAllShopCodeRedisCache(shopCodes);
            } catch (Exception e) {
                log.error("redis error：", e);
            }
        }
        return shopCodes;
    }

    private boolean checkDup(String shopCode, String shopName, Long id) {
        QueryWrapper<TShop> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().ne(TShop::getId, id).and(qw -> qw.eq(TShop::getShopCode, shopCode).or().eq(TShop::getShopName, shopName));
        List<TShop> ret = this.baseMapper.selectList(queryWrapper);
        return (null != ret && ret.size() > 1);
    }
}
